//
//  MTSeriaBase.swift
//  Clock
//
//  Created by 方强 on 16/7/5.
//  Copyright © 2016年 MT. All rights reserved.
//

import UIKit
import CoreBluetooth

public class MTSeriaBase: BLEBase {
    
    private var baseCallback = BLEBaseCallback();
    public override init(manager: MTBLEManager) {
        super.init(manager: manager);
        baseCallback.onCharactChanged = onMTSeriCharactChanged;
        baseCallback.onBaseConnect = onMTSeriBaseConnect;
        baseCallback.onDisConnect = onMTSeriBaseDisConnect;
        baseCallback.onManualDisConnect = onMTSeriBaseManualDisConnect;
    }
    
    // 连接
    private var callback:MTSeria_Callback!;
    public func connect(mac: String!, callback2: MTSeria_Callback, retryTimes: Int) -> ErroCode? {
        MTTools.logout(log: "connect->\(mac)");
        self.callback = callback2;
        connectfail = false;
        return super.connect(mac: mac, callback: baseCallback, retryTimes: retryTimes);
    }
    public func connect(device: MTBLEDevice!, callback2: MTSeria_Callback, retryTime: Int) -> ErroCode? {
        self.callback = callback2;
        connectfail = false;
        return super.connect(device: device, callback: baseCallback, retryTime: retryTime);
    }
    
    // 连接成功回调
    private var connectfail:Bool = false;
    private var connectfail_errocode:ErroCode?;
    private func onMTSeriBaseConnect(ble:BLEBase, erro:ErroCode?){
        MTTools.logout(log: "MTSeriaBase onMTSeriBaseConnect->\(erro?.getMsg())");
        
        if(erro?.getCode() != 0){  // 出错误的情况
            callback.onConnect?(self, erro!);
            return;
        }
        
        discoverServices();
    }
    
    // 获取特定服务
    private static let DATA_SERVICE_UUID = "F1F0";
    private static let TXD_CHARACT_UUID = "F1F1";
    private static let RXD_CHARACT_UUID = "F1F2";
    private static let CMD_SERVICE_UUID = "F2F0";
    private static let ATSEND_CHARACT_UUID = "F2F1";
    private static let ATRECV_CHARACT_UUID = "F2F2";
    private var txd_charact:CBCharacteristic?;
    private var rxd_charact:CBCharacteristic?;
    private var atsend_charact:CBCharacteristic?;
    private var atrecv_charact:CBCharacteristic?;
    // 发现服务
    private func discoverServices(){
        
        let action = DiscoverServicesAction(serviceuuids: nil, option: BLEBaseAction_ActionOption(timeout: 4000));
        action.onSuccess = {(action) in
            MTTools.logout(log: "discoverservices onSuccess");
            self.discoverCharacts();
        };
        action.onFail = {(action, errocode) in
            MTTools.logout(log: "discoverservices onFail->\(errocode.getMsg())");
            self.connectfail = true;
            self.connectfail_errocode = errocode;
            super.disConnect();
        };
        super.addNewAction(action: action);  // 等待4秒
    }
    
    // 发现特征值
    var data_service:CBService?;  // 判断获取到的service是否是需要的
    var cmd_service:CBService?;
    private func discoverCharacts(){
        
        let services = super.getAllServices();
        if(services == nil){  // 判断是否获取到service
            connectfail = true;
            connectfail_errocode = ErroCode.ERROMAP["getcharacterro"];
            super.disConnect();
            return;
        }
        
        for service in services! {
            if(service.uuid.uuidString == MTSeriaBase.DATA_SERVICE_UUID){
                data_service = service;
                continue;
            }
            if(service.uuid.uuidString == MTSeriaBase.CMD_SERVICE_UUID){
                cmd_service = service;
                continue;
            }
        }
        if((data_service == nil) || (cmd_service == nil)){
            connectfail = true;
            connectfail_errocode = ErroCode.ERROMAP["getcharacterro"];
            super.disConnect();
            return;
        }
        
        var action = DiscoverCharactsAction(service: data_service!, charactuuids: nil, option: BLEBaseAction_ActionOption(timeout: 2000));  // 添加发现数据特征值，等待2秒
        action.onSuccess = {(action) in
            MTTools.logout(log: "discoverCharacts onSuccess data_service");
            
        };
        action.onFail = {(action, errocode) in
            MTTools.logout(log: "discoverCharacts data_service onFail->\(errocode.getMsg())");
            self.connectfail = true;
            self.connectfail_errocode = errocode;
            super.disConnect();
        };
        super.addNewAction(action: action);
        
        action = DiscoverCharactsAction(service: cmd_service!, charactuuids: nil, option: BLEBaseAction_ActionOption(timeout: 2000));  // 添加发现命令特征值，等待2秒
        action.onSuccess = {(action) in
            MTTools.logout(log: "discoverCharacts onSuccess cmd_service");
            
            self.haveCharacts();
        };
        action.onFail = {(action, errocode) in
            MTTools.logout(log: "discoverCharacts cmd_service onFail->\(errocode.getMsg())");
            self.connectfail = true;
            self.connectfail_errocode = errocode;
            super.disConnect();
        };
        super.addNewAction(action: action);
    }
    
    // 判断是否有需要的特征值
    private func haveCharacts(){
        for charact in (data_service?.characteristics)! {
            if(charact.uuid.uuidString.uppercased() == MTSeriaBase.TXD_CHARACT_UUID){
                txd_charact = charact;
            }
            if(charact.uuid.uuidString.uppercased() == MTSeriaBase.RXD_CHARACT_UUID){
                rxd_charact = charact;
            }
        }
        
        for charact in (cmd_service?.characteristics)! {
            if(charact.uuid.uuidString.uppercased() == MTSeriaBase.ATSEND_CHARACT_UUID){
                atsend_charact = charact;
            }
            if(charact.uuid.uuidString.uppercased() == MTSeriaBase.ATRECV_CHARACT_UUID){
                atrecv_charact = charact;
            }
        }
        
        if ((txd_charact == nil) || (rxd_charact == nil) || (atsend_charact == nil) || (atrecv_charact == nil)) {
            connectfail = true;
            connectfail_errocode = ErroCode.ERROMAP["getcharacterro"];
            super.disConnect();
            return;
        }
        
        enableNotify();
        
    }
    
    // 开启notify
    private func enableNotify(){
        var action = SetNotifyAction(charact: rxd_charact, enable: true, option: BLEBaseAction_ActionOption(timeout: 1000));// 开启notify，等待1秒
        action.onSuccess = {(action) in
            
        };
        action.onFail = {(action, erro) in
            MTTools.logout(log: "discoverCharacts data_service onFail->\(erro.getMsg())");
            self.connectfail = true;
            self.connectfail_errocode = erro;
            super.disConnect();
        };
        super.addNewAction(action: action);
        
        action = SetNotifyAction(charact: atrecv_charact, enable: true, option: BLEBaseAction_ActionOption(timeout: 1000));// 开启notify，等待1秒
        action.onSuccess = {(action) in
            self.MTSericonnect = true;       // 连接成功
            self.callback.onConnect?(self, ErroCode.ERROMAP["OK"]!);
        };
        action.onFail = {(action, erro) in
            MTTools.logout(log: "discoverCharacts atrecv_charact onFail->\(erro.getMsg())");
            self.connectfail = true;
            self.connectfail_errocode = erro;
            super.disConnect();
        };
        
        super.addNewAction(action: action);
        
        addListCharact(charact: rxd_charact);     // 添加到监听列表
        addListCharact(charact: atrecv_charact);
    }
    
    // 断开回调
    private func onMTSeriBaseDisConnect(ble:BLEBase, erro:ErroCode){
        MTSericonnect = false;
        
        if(connectfail){  // 连接失败的时候，就不要继续回调断开
            connectfail = false;
            callback.onConnect?(self, connectfail_errocode!);
            return;
        }
        
        callback.onDisConnect?(self, erro);
    }
    
    // 主动断开
    private func onMTSeriBaseManualDisConnect(ble:BLEBase, erro:ErroCode){
        
        MTSericonnect = false;
        
        if(connectfail){  // 连接失败的时候，就不要继续回调断开
            connectfail = false;
            callback.onConnect?(self, connectfail_errocode!);
            return;
        }
        
        callback.onManualDisConnect?(self, erro);
    }
    
    // 查看可用连接状态
    private var MTSericonnect = false;
    public func isMTSericonnect() -> Bool{
        return (isConnected() && MTSericonnect);
    }

    // 监听到notify
    private func onMTSeriCharactChanged(ble:BLEBase, characteristic:CBCharacteristic, datas:Data?){
        MTTools.logout(log: "onMTSeriCharactChanged");
        if (characteristic == rxd_charact) { // 被动接受到数据
            callback.onDatasRecive?(self, datas);
            return;
        }
        
        if (characteristic == atrecv_charact) { // 被动接受到命令
            callback.onCmdRevice?(self, datas);
            return;
        }
    }

    // 添加写数据操作
    public func addWriteDatasAction(action:WriteCharactAction!) -> Bool{
        if(!isMTSericonnect()){
            return false;
        }
        action.setCharact(charact: txd_charact!);
        addNewAction(action: action);
        
        return true;
    }
    
    // 添加写数据带回复操作
    public func addWriteDatasWithAckAction(action:WriteCharactWithAckAction!) -> Bool{
        if(!isMTSericonnect()){
            return false;
        }
        action.setSendCharact(sendCharact: txd_charact);
        action.setReviceCharact(reviceCharact: rxd_charact);
        
        addNewAction(action: action);
        return true;
    }
    
    // 写命令操作
    public func addCmdAction(action:WriteCharactWithAckAction!) -> Bool{
        if(!isMTSericonnect()){
            return false;
        }
        action.setSendCharact(sendCharact: atsend_charact);
        action.setReviceCharact(reviceCharact: atrecv_charact);
        
        addNewAction(action: action);
        return true;
    }
    
}

public class MTSeria_Callback: NSObject{
    public override init() {
        super.init();
    }
    
    public var onConnect:((MTSeriaBase, ErroCode)->Void)?;
    public var reTryConnect:((MTSeriaBase, Int)->Void)?;
    public var onDisConnect:((MTSeriaBase, ErroCode)->Void)?;
    public var onManualDisConnect:((MTSeriaBase, ErroCode)->Void)?;
    public var onDatasRecive:((MTSeriaBase, Data?)->Void)?;
    public var onCmdRevice:((MTSeriaBase, Data?)->Void)?;
}

